package com.majun.config.standardfilter.sublogfilter;

import com.majun.config.standardfilter.ResponseWrapper;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper;
import org.springframework.web.util.WebUtils;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;


/**
 * 记录请求日志
 */
public class LogPrintFilter extends HttpFilter {

    private final Logger log = LoggerFactory.getLogger(LogPrintFilter.class);
    private static final long serialVersionUID = 8991118181953196532L;

    @Override
    protected void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        long requestTime = System.currentTimeMillis();
        // 请求方法
        String method = request.getMethod();
        String url = request.getRequestURL().toString();
        // 请求体
        String body = getRequestBody(request);
        if (StringUtils.isNotEmpty(body)) {
            body = body.replaceAll("\n", "");
        }
        final String params = getRequestParams(request);
        final String ip = getRequestIp(request);
        log.info("HttpRequest ===>>> method:[{}] url:[{}] params:[{}] body:[{}] ip:[{}] ", method, url, params, body, ip);
        long costTime = System.currentTimeMillis() - requestTime;
        // 继续执行请求链
        chain.doFilter(request, response);
        // 响应状态
        int status = response.getStatus();
        //测试验证是否获取到
        String data = getResponseBody(response);

        // 5. 包装 HttpServletResponse 对象为自定义的 ResponseWrapper 对象，以便后续的处理
//        ResponseWrapper responseWrapper = new ResponseWrapper(response);

        // 7. 获取响应数据
//        String data = responseWrapper.getResponseData(StandardCharsets.UTF_8.name());

        //打印响应体内容
        log.info("HttpResponse <<<=== status:[{}] data:[{}] costTime:[{}]", status, data, costTime);

        //非常关键
        ResponseWrapper responseWrapper = WebUtils.getNativeResponse(response, ResponseWrapper.class);

        //没有这一步，响应体为空
        responseWrapper.copyBodyToResponse();
//        // 8. 解析响应数据为JSON对象
//        JSONObject jsonData = JSONObject.parseObject(responseData);
//
//        // 9. 在这里可以对响应数据进行处理
//        jsonData.put("responseKey", "responseValue");
//
//        // 10. 将修改后的 JSON 对象转换为字符串
//        responseData = jsonData.toJSONString();

        // 11. 将修改后的 JSON 对象设置为最终的响应数据
//        responseWrapper.setResponseData(data, StandardCharsets.UTF_8.name());

        // 12. 将响应数据写入原始的响应对象，解决响应数据无法被多个过滤器处理问题
//        OutputStream outputStream = response.getOutputStream();
//        outputStream.write(data.getBytes(StandardCharsets.UTF_8));
//        outputStream.flush();

        //打印响应体内容
//        log.info("HttpResponse <<<=== status:[{}] costTime:[{}]", status, costTime);
        //打印响应体内容
//        log.info("HttpResponse <<<=== status:[{}] data:[{}] costTime:[{}]", status, data, costTime);

    }

    private String getRequestParams(final HttpServletRequest request) {
        Map<String, String[]> parameterMap = request.getParameterMap();
        final List<String> pairs = new ArrayList<>(10);
        if (MapUtils.isNotEmpty(parameterMap)) {
            for (final Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
                final String name = entry.getKey();
                final String[] value = entry.getValue();
                if (value == null) {
                    pairs.add(name + "=");
                } else {
                    for (final String v : value) {
                        pairs.add(name + "=" + StringUtils.trimToEmpty(v));
                    }
                }
            }
        }
        String requestParamsStr = CollectionUtils.isEmpty(pairs) ? StringUtils.EMPTY : String.join("&", pairs);
        if (StringUtils.equalsIgnoreCase(request.getContentType(), MediaType.APPLICATION_FORM_URLENCODED_VALUE)) {
            try {
                requestParamsStr = URLDecoder.decode(requestParamsStr, StandardCharsets.UTF_8.name());
            } catch (UnsupportedEncodingException ignored) {
            }
        }
        return requestParamsStr;
    }

    private String getRequestIp(final HttpServletRequest request) {
        String ip = request.getHeader("X-Real-IP");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("X-Forwarded-For");// 这是一个可以伪造的头
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getRemoteAddr();
            }
        }
        // 最后一个为RemoteAddr
        int pos = ip.lastIndexOf(',');
        if (pos >= 0) {
            ip = ip.substring(pos);
        }
        if ("0:0:0:0:0:0:0:1".equals(ip)) {
            ip = "127.0.0.1";
        }
        return ip;
    }

    private String getRequestBody(HttpServletRequest request) {
        int contentLength = request.getContentLength();
        if (contentLength <= 0) {
            return "";
        }
        String contentType = request.getContentType();
        if (contentType.startsWith(MediaType.APPLICATION_JSON_VALUE) || contentType.startsWith(MediaType.APPLICATION_XML_VALUE)){
            try {
                return IOUtils.toString(request.getReader());
            } catch (IOException e) {
                log.error("获取请求体失败", e);
            }
        }
        return "";
    }

    /**
     * 获取请求体
     *
     * @param request 请求对象
     * @return 请求体
     */
    private String getStandardRequestBody(HttpServletRequest request) throws IOException {
        String requestBody = "";
        ContentCachingRequestWrapper wrapper = WebUtils.getNativeRequest(request, ContentCachingRequestWrapper.class);
        if (wrapper != null) {
            requestBody = IOUtils.toString(wrapper.getContentAsByteArray(), StandardCharsets.UTF_8.toString());
        }
        return requestBody;
    }

    /**
     * 获取响应体
     *
     * @param response 响应对象
     * @return 响应体
     */
    private String getStandardResponseBody(HttpServletResponse response) throws IOException {
        String responseBody = "";
        ContentCachingResponseWrapper wrapper = WebUtils.getNativeResponse(response, ContentCachingResponseWrapper.class);
        if (wrapper != null) {
            responseBody = IOUtils.toString(wrapper.getContentAsByteArray(), StandardCharsets.UTF_8.toString());
        }
        return responseBody;
    }

    /**
     * 获取响应体
     *
     * @param response 响应对象
     * @return 响应体
     */
    private String getResponseBody(HttpServletResponse response) throws IOException {
        String responseBody = "";
        ResponseWrapper responseWrapper = WebUtils.getNativeResponse(response, ResponseWrapper.class);
        if (responseWrapper != null) {
            responseBody = IOUtils.toString(responseWrapper.getResponseBody(), StandardCharsets.UTF_8.name());
        }
        return responseBody;
    }
}